After building a base Gentoo system using OpenRC, everything functioned as expected except audio output. Players like mpv or ffplay reported no errors, but no sound was produced. This wasn’t due to ALSA itself failing aplay -l showed hardware devices, and /proc/asound/cards was populated. The issue was absence of a sound server managing the userland routing...
On more guided distributions, something like pipewire-pulse is pulled automatically by metapackages or profile defaults. Gentoo requires explicit configuration. I chose PipeWire without running the PulseAudio daemon, but kept compatibility via libpulse.
The audio stack behavior depends heavily on USE flags. Here's the relevant setup:
# /etc/portage/make.conf USE="-qt5 -kde -telemetry X pulseaudio"
The global pulseaudio USE flag is needed for packages like SDL2, libcanberra, or anything that links against libpulse. However, I did not want the PulseAudio daemon to be built or installed.
To achieve that:
# /etc/portage/package.use/pulseaudio media-sound/pulseaudio -daemon
This disables the init/startup part of PulseAudio while keeping the client library. Simultaneously, I needed PipeWire to act as the actual sound server:
# /etc/portage/package.use/pipewire media-video/pipewire sound-server
Executed the following:
emerge --ask media-video/pipewire emerge --ask media-video/wireplumber emerge --ask sys-auth/rtkit
wireplumber is necessary as the session manager. Without it, PipeWire’s services start but remain inert, no nodes are created, and no audio routing occurs. rtkit provides real-time priority handling, which is required by PipeWire to set thread priorities via SCHED_RR. On OpenRC, this is not automatically available unless rtkit is present and its service started.
Also added the user to the pipewire group:
usermod -aG pipewire rian
Although not always necessary, some setups especially with custom PAM or seatd handling benefit from explicit group permissions.
PipeWire’s default configuration is located in /usr/share/pipewire. To allow for user-specific overrides:
mkdir -p ~/.config/pipewire/ cp /usr/share/pipewire/pipewire.conf ~/.config/pipewire/
System-wide:
cp /usr/share/pipewire/pipewire.conf /etc/pipewire/
If using pipewire-pulse, it binds to $XDG_RUNTIME_DIR/pipewire-0 and creates a Pulse-compatible socket at $XDG_RUNTIME_DIR/pulse/native. That’s how programs linked against libpulse are transparently routed to PipeWire without reconfiguration.
You can confirm this by:
pactl info
Which should report: Server Name: PulseAudio (on PipeWire X.Y.Z)
PipeWire does not provide native OpenRC scripts. I created a local init file in /etc/init.d/pipewire, wrapping pipewire and pipewire-pulse, then added it to default:
rc-update add pipewire default
Alternatively, one can manage it via per-user autostart if running a desktop session, especially under X or Wayland.
With this configuration, PipeWire serves as the active sound server, replacing the PulseAudio daemon entirely. libpulse is still available for compatibility, but no extra daemon is launched. The system remains minimal, controlled, and fully functional in audio without systemd or extraneous layers.